package ua.com.globallogic.basecamp.krasnyanskiy.dds.queue;

import java.util.NoSuchElementException;

public class SimpleQueue<E> {

    private Node<E> first;
    private Node<E> last;

    private static class Node<E> {
        E value;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.value = element;
            this.next = next;
            this.prev = prev;
        }
    }


    /* adds the element to the tail of queue */
    public boolean offer(E elem) {
        Node<E> node = last;
        Node<E> newNode = new Node<E>(node, elem, null);
        last = newNode;
        if (node == null) {
            first = newNode;
        } else {
            node.next = newNode;
        }
        return true;
    }


    /* deletes the first element from queue */
    public E remove() {
        Node<E> f = first;
        E elem = (f == null) ? null : getAndDeleteFirst(f);
        if (elem == null) {
            throw new NoSuchElementException();
        }
        return elem;
    }


    /* deletes the first element of queue and returns it */
    private E getAndDeleteFirst(Node<E> node) {
        Node<E> next = node.next;
        E elem = node.value;
        node.value = null;
        node.next = null;
        first = next;

        if (next == null) {
            last = null;
        } else {
            next.prev = null;
        }

        return elem;
    }


    /* retrieves and removes the first element of queue */
    public E poll() {
        Node<E> node = first;
        if (node == null) {
            return null;
        } else {
            return getAndDeleteFirst(node);
        }
    }


    /* retrieves the first of queue */
    public E element() {
        Node<E> node = first;
        if (node == null) {
            throw new NoSuchElementException();
        }
        return node.value;
    }


    /* retrieves the first element of queue */
    public E peek() {
        Node<E> node = first;
        return (node == null)
                ? null
                : node.value;
    }
}
